﻿#region Copyright (c) 2013-05, Olaf Kober <amarok.projects@gmail.com>
//================================================================================
//	Permission is hereby granted, free of charge, to any person obtaining a copy
//	of this software and associated documentation files (the "Software"), to deal
//	in the Software without restriction, including without limitation the rights
//	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//	copies of the Software, and to permit persons to whom the Software is
//	furnished to do so, subject to the following conditions:
//
//	The above copyright notice and this permission notice shall be included in
//	all copies or substantial portions of the Software.
//
//	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//	THE SOFTWARE.
//================================================================================
#endregion

using System;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Markup;
using System.Windows.Media;
using Amarok.Presentation.Native;
using Amarok.Presentation.Resources;


namespace Amarok.Presentation
{
	/// <summary>
	/// This type contains helper routines specific to WPF (Windows Presentation Foundation).
	/// </summary>
	public static class Wpf
	{
		private const Double __PointsPerInch = 72.0;
		private const Double __PixelPerInch = 96.0;
		private const Double __MillimeterPerInch = 25.4;


		#region ++ Public Static Interface (ToPixel) ++

		/// <summary>
		/// Converts the given value in inches into device-independent pixels.
		/// </summary>
		public static Double InchToPixel(Double valueInInch)
		{
			return valueInInch * __PixelPerInch;
		}

		/// <summary>
		/// Converts the given value in millimeters into device-independent pixels.
		/// </summary>
		public static Double MillimeterToPixel(Double valueInMillimeter)
		{
			return valueInMillimeter * __PixelPerInch / __MillimeterPerInch;
		}

		#endregion

		#region ++ Public Static Interface (ToMillimeter) ++

		/// <summary>
		/// Converts the given value in inches into millimeters.
		/// </summary>
		public static Double InchToMillimeter(Double valueInInch)
		{
			return valueInInch * __MillimeterPerInch;
		}

		/// <summary>
		/// Converts the given value in device-independent pixels into millimeters.
		/// </summary>
		public static Double PixelToMillimeter(Double valueInPixel)
		{
			return valueInPixel * __MillimeterPerInch / __PixelPerInch;
		}

		#endregion

		#region ++ Public Static Interface (ToInch) ++

		/// <summary>
		/// Converts the given value in millimeters into inches.
		/// </summary>
		public static Double MillimeterToInch(Double valueInMillimeter)
		{
			return valueInMillimeter / __MillimeterPerInch;
		}

		/// <summary>
		/// Converts the given value in device-independent pixel into inches.
		/// </summary>
		public static Double PixelToInch(Double valueInPixel)
		{
			return valueInPixel / __PixelPerInch;
		}

		#endregion

		#region ++ Public Static Interface (Font Size) ++

		/// <summary>
		/// Converts the given font size in points (72 DPI) into device-independent pixel (96 DPI).
		/// </summary>
		public static Double FontSizePointToPixel(Double valueInPoint)
		{
			return valueInPoint * __PixelPerInch / __PointsPerInch;
		}

		/// <summary>
		/// Converts the given font size in device-independent pixels (96 DPI) into points (72 DPI).
		/// </summary>
		public static Double FontSizePixelToPoint(Double valueInPixel)
		{
			return valueInPixel * __PointsPerInch / __PixelPerInch;
		}

		#endregion

		#region ++ Public Static Interface (Override Defaults) ++

		/// <summary>
		/// Overrides the default value of <see cref="TextOptions.TextFormattingModeProperty"/> on all instances of 
		/// type <see cref="FrameworkElement"/>. You should call this method before the first instance of an UI element 
		/// is created, otherwise you will get inconsistent results.
		/// </summary>
		/// 
		/// <param name="textFormattingMode">
		/// Optional. The new default value for <see cref="TextOptions.TextFormattingModeProperty"/>. Defaults to 
		/// <see cref="TextFormattingMode.Display"/>.</param>
		/// 
		/// <exception cref="ArgumentException">
		/// Metadata was already established for the dependency property as it exists on the provided type.</exception>
		public static void OverrideTextFormattingModeDefault(TextFormattingMode textFormattingMode = TextFormattingMode.Display)
		{
			TextOptions.TextFormattingModeProperty.OverrideMetadata(
				typeof(FrameworkElement),
				new FrameworkPropertyMetadata(textFormattingMode)
			);
		}

		/// <summary>
		/// Overrides the default value of <see cref="FrameworkElement.LanguageProperty"/> on all instances of type 
		/// <see cref="FrameworkElement"/>. You should call this method before the first instance of an UI element 
		/// is created, otherwise you will get inconsistent results.
		/// </summary>
		/// 
		/// <param name="language">
		/// Optional. The new default value for <see cref="FrameworkElement.LanguageProperty"/>. Defaults to 
		/// <see cref="CultureInfo.CurrentCulture"/> if null is specified.</param>
		/// 
		/// <exception cref="ArgumentException">
		/// Metadata was already established for the dependency property as it exists on the provided type.</exception>
		public static void OverrideLanguageDefault(CultureInfo language = null)
		{
			language = language ?? CultureInfo.CurrentCulture;

			FrameworkElement.LanguageProperty.OverrideMetadata(
				typeof(FrameworkElement),
				new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(language.IetfLanguageTag))
			);
		}

		#endregion

		#region ++ Public Static Interface (Dialog) ++

		/// <summary>
		/// Changes the style of the given window to a dialog, i.e. removing the minimize and maximize boxes.
		/// </summary>
		/// 
		/// <param name="window">
		/// The window which style should be changed.</param>
		/// 
		/// <exception cref="ArgumentNullException">
		/// A null reference was passed to a method that did not accept it as a valid argument.</exception>
		public static void SetupDialogWindowStyle(Window window)
		{
			Verify.NotNull(window, "window");

			const Int32 GWL_STYLE = -16;
			const Int32 WS_MAXIMIZEBOX = 0x00010000;
			const Int32 WS_MINIMIZEBOX = 0x00020000;

			var interopHelper = new WindowInteropHelper(window);
			var hwnd = new HandleRef(window, interopHelper.Handle);

			if (IntPtr.Size == 4)
			{
				Int32 windowStyle = NativeWindow.GetWindowLongPtr(hwnd, GWL_STYLE).ToInt32();
				windowStyle = windowStyle & ~WS_MAXIMIZEBOX & ~WS_MINIMIZEBOX;
				NativeWindow.SetWindowLongPtr(hwnd, GWL_STYLE, new IntPtr(windowStyle));
			}
			else if (IntPtr.Size == 8)
			{
				Int64 windowStyle = NativeWindow.GetWindowLongPtr(hwnd, GWL_STYLE).ToInt64();
				windowStyle = windowStyle & ~WS_MAXIMIZEBOX & ~WS_MINIMIZEBOX;
				NativeWindow.SetWindowLongPtr(hwnd, GWL_STYLE, new IntPtr(windowStyle));
			}
			else
			{
				throw new NotSupportedException(ExceptionResources.PlatformNotSupported);
			}
		}

		#endregion

	}
}
